﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System;

namespace TestScaner
{
   public class DeterministicFSM{
      private readonly List<string> Q = new List<string>();
      private readonly List<char> Sigma = new List<char>();
      private readonly List<Transition> Delta = new List<Transition>();
      private string Q0;
      private string Q48 = "49";//Starea de eroare.
      private readonly List<string> F = new List<string>();
     
      public DeterministicFSM(IEnumerable<string> q, IEnumerable<char> sigma, IEnumerable<Transition> delta, string q0, IEnumerable<string> f){
         Q = q.ToList();
         Sigma = sigma.ToList();
         Delta = delta.ToList<Transition>();
         Q0 = q0;
         F = f.ToList<string>();
      }

      private void AddTransitions(IEnumerable<Transition> transitions){
         foreach (var transition in transitions.Where(ValidTransition)){
            Delta.Add(transition);
         }
      }

      private bool ValidTransition(Transition transition){
         return Q.Contains(transition.StartState) &&
                Q.Contains(transition.EndState) &&
                Sigma.Contains(transition.Symbol) &&
                !TransitionAlreadyDefined(transition);
      }

      private bool TransitionAlreadyDefined(Transition transition){
         return Delta.Any(t => t.StartState == transition.StartState &&
                               t.Symbol == transition.Symbol);
      }

      private void AddInitialState(string q0){
         if (q0 != null && Q.Contains(q0)){
            Q0 = q0;
         }
      }

      private void AddFinalStates(IEnumerable<string> finalStates){
         foreach (var finalState in finalStates.Where(finalState => Q.Contains(finalState))){
            F.Add(finalState);
         }
      }

      public string Accepts(string input)
      {
         if (InvalidInputOrFSM(input))
         {
            return "49";
         }
         var currentState = Q0;
         var antState = Q48;
         var steps = new StringBuilder();
         foreach (var symbol in input.ToCharArray())
         {
             var transition = Delta.Find(t => (t.StartState == currentState &&
                                              t.Symbol == symbol));

            if (transition == null)
            {
               return antState;
            }
            currentState = transition.EndState;
            antState = currentState;
         }
         return antState;
      }

      public string Accepts(string currentState,char c)
      {
          var transition = Delta.Find(t => (t.StartState == currentState &&
                                               t.Symbol == c));
          if (transition == null)
          {     
             return "q49";
          }

          return transition.EndState;
      }

      private Transition nextState(string currentState,char symbol)
      {
          foreach (Transition t in Delta)
              if (t.StartState == currentState && t.Symbol == symbol)
                  return t;
          return null;
      }

      private bool InvalidInputOrFSM(string input)
      {
         if (InputContainsNotDefinedSymbols(input))
         {
            return true;
         }
         if (InitialStateNotSet())
         {
            return true;
         }
         if (NoFinalStates())
         {
            return true;
         }
         return false;
      }

      private bool InputContainsNotDefinedSymbols(string input)
      {
         foreach (var symbol in input.ToCharArray().Where(symbol => !Sigma.Contains(symbol)))
         {
            return true;
         }
         return false;
      }

      private bool InitialStateNotSet()
      {
         return string.IsNullOrEmpty(Q0);
      }

      private bool NoFinalStates()
      {
         return F.Count == 0;
      }
   }
}
